#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>

union semun
{
    int val;
};
union semun su;

int Get_random()
{
    int digit;
    srand((unsigned)(time(NULL)));
    digit = rand() % 1;
    printf("time is %d\n", digit);
    return digit;
};

char Get_letter()
{
    char m = '0';
    int r = rand() % (9) + 0;
    return (char)(m + r);
};

void P(int sem_id, int sem_num)
{
    struct sembuf xx;
    xx.sem_num = sem_num;  //信号量的索引
    xx.sem_op = -1;        //信号量的操作值
    xx.sem_flg = 0;        //访问标志
    semop(sem_id, &xx, 1); //一次需进行的操作的数组sembuf中的元素数为1
};

//V操作
void V(int sem_id, int sem_num)
{
    struct sembuf xx;
    xx.sem_num = sem_num;
    xx.sem_op = 1;
    xx.sem_flg = 0;
    semop(sem_id, &xx, 1);
};

struct Buffer
{
    char buf[6][10];
    int Buffer_Head;
    int Buffer_End;
    int Buffer_Is_Empty;
};

int main(int argc, char *argv[])
{
    pid_t pidP, pidC;
    struct Buffer *buffer;
    int sem_id, shm_id;
    time_t now;
    struct tm *timenow;

    //创建一个信号量集合(信号量数为2)，返回值为信号量集合的标识号(关键字，信号量数，创建或打开的标志)
    sem_id = semget(1234, 3, IPC_CREAT | 0644);

    //对信号量执行控制操作(信号量集合标识，信号量的索引，要执行的操作命令，设置或返回信号量的参数)
    su.val = 6;
    semctl(sem_id, 0, SETVAL, su);
    su.val = 0;
    semctl(sem_id, 1, SETVAL, su);
    su.val = 1;
    semctl(sem_id, 2, SETVAL, su);

    //申请一个共享内存区，成功返回为共享内存区的标识
    shm_id = shmget(IPC_PRIVATE, sizeof(struct Buffer), 0600);

    //将共享段附加到申请通信的进程空间；成功时返回共享内存附加到进程空间的虚地址，失败时返回-1
    buffer = shmat(shm_id, 0, 0);

    buffer->Buffer_End = 0;
    buffer->Buffer_Head = 0;
    buffer->Buffer_Is_Empty = 1;

    printf("MAIN PROCESS GOING!\n");

    for (int p = 1; p <= 2; p++)
    {
        char con[10];
        pidP = fork();
        if (pidP < 0)
            printf("Failed to Producer Process!\n");

        if (pidP == 0)
        {
            buffer = shmat(shm_id, 0, 0);
            for (int i = 0; i < 12; i++)
            {
            sleep(Get_random());
                P(sem_id, 0);
                P(sem_id, 2);
                // printf("pgoooal\n");
                
                // printf("pgoooal2\n");
                for (int i = 0; i < 9; i++)
                    con[i] = Get_letter();
                con[9] = '\0';
                for (int i = 0; i < 9; i++)
                    buffer->buf[buffer->Buffer_End][i] = con[i];

                buffer->Buffer_End = (buffer->Buffer_End + 1) % 6;

                buffer->Buffer_Is_Empty = 0;
                time(&now);
                timenow = localtime(&now);
                now = time(NULL);
                printf("%02d:%02d:%02d    ", timenow->tm_hour, timenow->tm_min, timenow->tm_sec);

                int j = (buffer->Buffer_End - 1 >= buffer->Buffer_Head) ? (buffer->Buffer_End - 1) : (buffer->Buffer_End - 1 + 6);
                for (j; !(buffer->Buffer_Is_Empty) && j >= buffer->Buffer_Head; j--)
                {
                    printf("%s   ", buffer->buf[j % 6]);
                }


                printf("   生产者---%d---放入---'%s'---#%d\n", p, con, i);
                fflush(stdout);
                V(sem_id, 2);
                V(sem_id, 1);
            }
            shmdt(buffer);
            exit(0);
        }
    }

    for (int p = 3; p <= 5; p++)
    {
        char con[10];
        pidC = fork();
        if (pidC < 0)
            printf("Failed to CONSUMER Process!\n");
        if (pidC == 0)
        {
            buffer = shmat(shm_id, 0, 0);
            for (int i = 0; i < 8; i++)
            {

                P(sem_id, 1);
                P(sem_id, 2);
                //  printf("cgoooal\n");
                sleep(Get_random());
                //  printf("cgoooal2\n");
                for (int i = 0; i < 10; i++)
                    con[i] = buffer->buf[buffer->Buffer_Head][i];
                buffer->Buffer_Head = (buffer->Buffer_Head + 1) % 6;
                buffer->Buffer_Is_Empty = (buffer->Buffer_Head == buffer->Buffer_End);

                time(&now);
                timenow = localtime(&now);
                now = time(NULL);
                printf("%02d:%02d:%02d    ", timenow->tm_hour, timenow->tm_min, timenow->tm_sec);

                int j = (buffer->Buffer_End - 1 >= buffer->Buffer_Head) ? (buffer->Buffer_End - 1) : (buffer->Buffer_End - 1 + 6);
                for (j; !(buffer->Buffer_Is_Empty) && j >= buffer->Buffer_Head; j--)
                {
                    printf("%s     ", buffer->buf[j % 6]);
                }
                printf("    消费者---%d---取出---'%s'---#%d\n", p, con, i);
                fflush(stdout);
                V(sem_id, 2);
                V(sem_id, 0);
            }
            shmdt(buffer);
            exit(0);
        }
    }

    while (wait(0) != -1)
        ;
    //将共享段与进程之间解除连接
    shmdt(buffer);
    //对共享内存区执行控制操作
    shmctl(shm_id, IPC_RMID, 0); //当cmd为IPC_RMID时，删除该共享段
    shmctl(sem_id, IPC_RMID, 0);
    printf("MAIN PROCESS FINISH!\n");

    fflush(stdout);
    exit(0);
}
